package com.pig4cloud.pig.common.data.methods;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;

import java.util.Map;
import java.util.stream.Collectors;

import static cn.hutool.core.util.ClassUtil.getClassName;
import static cn.hutool.core.util.StrUtil.*;
import static com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils.convertForeach;
import static com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils.convertTrim;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

public abstract class BaseAbstractMethod extends AbstractMethod {

    protected Dict getInster(TableInfo tableInfo, Class idName) {
        KeyGenerator keyGenerator = new NoKeyGenerator();
        String keyProperty = null;
        String keyColumn = null;
        // 表包含主键处理逻辑,如果不包含主键当普通字段处理
        if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
            if (tableInfo.getIdType() == IdType.AUTO) {
                /** 自增主键 */
                keyGenerator = new Jdbc3KeyGenerator();
                keyProperty = tableInfo.getKeyProperty();
                keyColumn = tableInfo.getKeyColumn();
            } else {
                if (null != tableInfo.getKeySequence()) {
                    keyGenerator = TableInfoHelper.genKeyGenerator(getClassName(idName, true), tableInfo, builderAssistant);
                    keyProperty = tableInfo.getKeyProperty();
                    keyColumn = tableInfo.getKeyColumn();
                }
            }
        }
        return new Dict().set("keyGenerator", keyGenerator).set("keyProperty", keyProperty).set("keyColumn", keyColumn);
    }

    /**
     * 获取if标签语句
     *
     * @param newLine
     * @param prefix
     * @return
     */
    protected String sqlContext(TableInfo tableInfo, boolean newLine, String prefix) {
        Map<String, String> list = tableInfo.getFieldList().parallelStream().collect(Collectors.toMap(TableFieldInfo::getColumn, TableFieldInfo::getProperty));

        String last = list.entrySet().stream().map(entry -> entry.getKey()).collect(toList()).subList(list.size() - 1, list.size()).toString()
                .replace("[", "").replace("]", "")
                ;

        return list.entrySet().parallelStream().map(i -> convertIf(i.getValue(), i.getValue(), newLine, i.getKey().equalsIgnoreCase(last), prefix)).collect(toList()).parallelStream().collect(joining());
    }

    /**
     * <p>
     * 获取 带 if 标签的脚本（来自SqlScriptUtils.convertIf）
     * </p>
     *
     * @param sqlScript sql 脚本片段
     * @return if 脚本
     */
    protected String convert(final String sqlScript, final String ifTest, boolean newLine, boolean isLast, String prefix) {
        return baseConvertIf(sqlScript, ifTest, newLine, isLast, prefix, false);
    }

    /**
     * <p>
     * 获取 带 if 标签的脚本（来自SqlScriptUtils.convertIf）
     * </p>
     *
     * @param sqlScript sql 脚本片段
     * @return if 脚本
     */
    protected String convertIf(final String sqlScript, final String ifTest, boolean newLine, boolean isLast, String prefix) {
        return baseConvertIf(sqlScript, ifTest, newLine, isLast, prefix, true);
    }


    /**
     * 生成字段或值
     * @param sqlScript
     * @param ifTest
     * @param newLine
     * @param isLast
     * @param prefix
     * @param isIf
     * @return
     */
    protected String baseConvertIf(final String sqlScript, final String ifTest, boolean newLine, boolean isLast, String prefix, boolean isIf) {
        // 值
        String newSqlScriptText = isLast ? isNotBlank(prefix) ? HASH_LEFT_BRACE + prefix + sqlScript + RIGHT_BRACE : HASH_LEFT_BRACE + sqlScript + RIGHT_BRACE :
                isNotBlank(prefix) ? HASH_LEFT_BRACE + prefix + sqlScript + RIGHT_BRACE + COMMA : HASH_LEFT_BRACE + sqlScript + RIGHT_BRACE + COMMA,

                // if语句
                ifContext = isIf ? format("<if test=\"{a}\">{b}</if>", new Dict().set("a", StrUtil.format("{a} != null and {a} != ''", new Dict().set("a", ifTest))).set("b", newSqlScriptText)) : newSqlScriptText;

        return newLine ? NEWLINE + ifContext : ifContext;
    }

    /**
     * 获取SqlSource
     * @param sql 需拼接sql
     * @param modelClass
     * @param tableInfo 数据库表信息
     * @param dict sql的字段和列
     * @param isId 是否插入主键
     * @param isTrim 是否加<trim></trim>
     * @param isFor 是否for循环
     * @return
     */
    protected SqlSource sqlSource(String sql, Class<?> modelClass, TableInfo tableInfo, Dict dict, boolean isId, boolean isTrim, boolean isFor) {
        // 字段
        String a = convertTrim(String.valueOf(dict.get("a"))
                // .replace(tableInfo.getKeyProperty()+",","")
                , "(", ")", null, ",");
        // 列
        String b = null;
        if (isFor) {
            b = isId ? convertForeach("#{" + tableInfo.getKeyProperty() + "}," + dict.getStr("b"), COLLECTION, null, "item", COMMA) : convertForeach(dict.getStr("b"), COLLECTION, null, "item", COMMA);
        } else {
            b = isId ? isTrim ? convertTrim("#{" + tableInfo.getKeyProperty() + "}," + dict.getStr("b"), "(", ")", null, null) : "#{" + tableInfo.getKeyProperty() + "}," + dict.getStr("b")
                    : isTrim ? convertTrim(dict.getStr("b"), "(", ")", null, null) : dict.getStr("b");
        }
        Dict set = new Dict().set("a", a).set("b", b).set("c", dict.get("c"));
        return languageDriver.createSqlSource(configuration, format(sql, set), modelClass);
    }


    /**
     * 重新定义插入的构造模式（修改来自父类的：addInsertMappedStatement）
     *
     * @param mapperClass
     * @param parameterType
     * @param idName
     * @param sqlSource
     * @return
     */
    protected MappedStatement insertMappedStatement(Class<?> mapperClass, Class<?> parameterType, Class<?> idName,
                                                    SqlSource sqlSource, TableInfo tableInfo) {
        Dict data = getInster(tableInfo,idName);
        return addMappedStatement(mapperClass, lowerFirst(getClassName(idName, true)), sqlSource, SqlCommandType.INSERT, parameterType, null,
                Integer.class,
                new NoKeyGenerator(), null, null
                // data.getBean("keyGenerator"), data.getStr("keyProperty"), data.getStr("keyColumn")
        );
    }

}
